﻿

#include <iostream>
using namespace std;

template<class T>
void f1(T& t)
{
	int a = 0;
	/*T x = a;

	cout << &a << " "<< &x << endl;*/
}

// 由于引⽤折叠限定，f2实例化后可以是左值引⽤，也可以是右值引⽤
template<class T>
void f2(T&& t)
{
	/*int a = 0;
	T x = a;

	cout << &a << " " << &x << endl;*/
}

void Test1()
{
	int n = 0;

	// 没有折叠->实例化为void f1(int& x)
	f1<int>(n);
	//f1<int>(0); // ERR “void f1<int>(T &)”: 无法将参数 1 从“int”转换为“T &”

	// 折叠->实例化为void f1(int& x)
	f1<int&>(n);
	//f1<int&>(0); // ERR “void f1<int>(T &)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f1(int& x)
	f1<int&&>(n);
	//f1<int&&>(0); // ERR “void f1<int&&>(T)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f1(const int& x)
	f1<const int&>(n);
	f1<const int&>(0);

	// 折叠->实例化为void f1(const int& x)
	f1<const int&&>(n);
	f1<const int&&>(0);

	// 没有折叠->实例化为void f2(int&& x)
	//f2<int>(n); // ERR “void f2<int>(T &&)”: 无法将参数 1 从“int”转换为“T &&”
	f2<int>(0);

	// 折叠->实例化为void f2(int& x)
	f2<int&>(n);
	//f2<int&>(0); // ERR “void f2<int&>(T)”: 无法将参数 1 从“int”转换为“T”

	// 折叠->实例化为void f2(int&& x)
	//f2<int&&>(n); // ERR “void f2<int&&>(T)”: 无法将参数 1 从“int”转换为“T”
	f2<int&&>(0);
}

template<class T>
void Function1(T& t)
{
	int a = 0;
	T x = a;

	//x++;	// const对象无法修改
	cout << &a << endl;
	cout << &x << endl;
}

template<class T>
void Function2(T&& t)
{
	int a = 0;
	T x = a;

	//x++;
	cout << &a << endl;
	cout << &x << endl << endl;
}

// 编译器自动推导T的类型
void Test2()
{
	cout << "************右值************" << endl;
	//Function1(10);		// ERR
	Function2(10);			// 10是右值，推导出T为int，模板实例化为void Function2(int&& t)

	int a = 10;

	cout << "************左值************" << endl;
	Function1(a);			// a是左值，推导出T为int，模板实例化为void Function(int& t)
	Function2(a);			// a是左值，推导出T为int&，int& && 引⽤折叠为 int&，模板实例化为void Function2(int& t)

	cout << "********move(左值)***********" << endl;
	//Function1(std::move(a)));	// ERR
	Function2(std::move(a));	// std::move(a)是右值，推导出T为int，模板实例化为void Function2(int&& t)

	const int b = 8;

	cout << "**********const 左值**********" << endl;
	Function1(b);			// b是左值，推导出T为const int，模板实例化为void Function1(const int& t)
	Function2(b);			// b是左值，推导出T为const int&，const int& && 引⽤折叠为 const int&，模板实例化为void Function2(const int& t)
							// Function1和Function2内部的x++均会编译报错（“x”: 不能给常量赋值）

	cout << "**********const 右值**********" << endl;
	Function1(std::move(b)); //	std::move(b)表达式的结果是右值，b的基础类型仍是int，推导出T为const int，模板实例化为void Function(const int& t)
	Function2(std::move(b)); // std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&& t)
							 // Function1和Function2内部的x++均会编译报错（“x”: 不能给常量赋值）

	const int&& c = move(a);
	const int& lc = a;
}

int main()
{
	Test1();
	Test2();

	return 0;
}